package jmetal.metaheuristics.dnsgaii;

import java.util.Comparator;

import jmetal.core.Algorithm;
import jmetal.core.Operator;
import jmetal.core.Problem;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;
import jmetal.util.ExtremumPoint;
import jmetal.util.JMException;
import jmetal.util.Ranking;
import jmetal.util.SingletonExtremePoint;
import jmetal.util.SingletonReferenceVector;
import jmetal.util.comparators.FitnessComparator;
import jmetal.util.dir.OccupyFitness;

/**
 * the algortihm d-NSGA-II
 * @author Haoran Sun
 *
 */
public class DNSGAII extends Algorithm{
	
	private static final String outDirect = "output_data/dnsga2/";
	private static final long serialVersionUID = 6491179879661463650L;
	Operator mutationOperator;
	Operator crossoverOperator;
	Operator selectionOperator;
	int populationSize;
	int maxEvaluations;
	int evaluations;//当前evaluation 次数
	double[] zideal;
	double[] intercepts;
	double[][] vectors;
	
	boolean isNormalize = true;
	
	public DNSGAII(Problem problem) {
		super(problem);
	}


	@Override
	public SolutionSet execute() throws JMException, ClassNotFoundException {

		initializeAlg();
		
		
		SolutionSet population = initilizePopulation(); 
//		int itr = 0;
		generate(population);
		SingletonExtremePoint.freePoint();
		Ranking ranking = new Ranking(population);
		return ranking.getSubfront(0);
	}


	private void generate(SolutionSet population) throws JMException {
		int iteration = 0;
		while(evaluations < maxEvaluations){
			if(iteration % 10 == 0){
				String fileName = outDirect + getProblem().getName() + "/FUN_" 
						+ getProblem().getNumberOfObjectives() + "D_0_PROC/FUN" + (iteration / 10);
				population.printObjectivesToFile(fileName);
			}
			
			SolutionSet offspringPopulation = generateOffspring(population);
			SolutionSet union = population.union(offspringPopulation);
			
			zideal = ExtremumPoint.getIdealPoint(union);
			intercepts = ExtremumPoint.getInterceptPoint(union);
			
			Ranking rank = new Ranking(union);
	        int remain = populationSize;
	        int index = 0;
	        SolutionSet front = null;
	        population.clear();
	        
	        front = rank.getSubfront(index);
	        while(remain>0&&remain>front.size()){
				for (int k = 0; k < front.size(); k++) {
					population.add(front.get(k));
				}
				remain = remain-front.size();
				index++;
				if(remain>0){
					front = rank.getSubfront(index);
				}
	        }
	        if(remain>0){
	        	SolutionSet unionSet = population.union(front);
	        	OccupyFitness fitness = new OccupyFitness(unionSet);
	        	if(isNormalize)
	        		fitness.assignFitness(vectors,zideal,intercepts);
	        	else fitness.assignFitness(vectors);
	        	
	        	@SuppressWarnings("rawtypes")
				Comparator comparator = new FitnessComparator();
	        	
	        	front.sort(comparator);
	        	
	        	for(int i = 0;i<remain;i++)
	        		population.add(front.get(i));
	        }
	        iteration++ ;
		}
	}

	private SolutionSet generateOffspring(SolutionSet population) throws JMException {
		SolutionSet offspringPopulation;
		offspringPopulation = new SolutionSet(populationSize);
		Solution[] parents = new Solution[2];
		for(int i=0;i<(populationSize/2);i++){
			if(evaluations<maxEvaluations){
				parents[0] = (Solution) selectionOperator.execute(population);
				parents[1] = (Solution) selectionOperator.execute(population);
				Solution[] offSpring = (Solution[]) crossoverOperator.execute(parents);
				mutationOperator.execute(offSpring[0]);
				mutationOperator.execute(offSpring[1]);
				problem_.evaluate(offSpring[0]);
				problem_.evaluateConstraints(offSpring[0]);
				problem_.evaluate(offSpring[1]);
				problem_.evaluateConstraints(offSpring[1]);
				offspringPopulation.add(offSpring[0]);
				offspringPopulation.add(offSpring[1]);
				evaluations += 2;
			}
		}
		return offspringPopulation;
	}

	private void initializeAlg() {
		// Read the parameters
		populationSize = ((Integer) getInputParameter("populationSize")).intValue();
		maxEvaluations = ((Integer) getInputParameter("maxEvaluations")).intValue();
		evaluations = 0;
		// Read the operators
		mutationOperator = operators_.get("mutation");
		crossoverOperator = operators_.get("crossover");
		selectionOperator = operators_.get("selection");
		isNormalize = (boolean) getInputParameter("normalization");
		int numberObjectives = problem_.getNumberOfObjectives();
		zideal = new double[numberObjectives];
		intercepts = new double[numberObjectives];
		vectors = SingletonReferenceVector.getReferenceVectors(numberObjectives, populationSize);
	}

	
	private SolutionSet initilizePopulation()
			throws ClassNotFoundException, JMException {
		SolutionSet population = new SolutionSet(populationSize);
		Solution newSolution;
		for (int i = 0; i < populationSize; i++) {
			newSolution = new Solution(problem_);
			problem_.evaluate(newSolution);
			problem_.evaluateConstraints(newSolution);
			evaluations++;
			population.add(newSolution);
		}
		return population;
	}
	
}
